package com.bruce.tool.push.aliyun.core;

import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.http.ProtocolType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;
import com.aliyuncs.push.model.v20160801.PushRequest;
import com.aliyuncs.push.model.v20160801.PushResponse;
import com.aliyuncs.utils.ParameterHelper;
import com.bruce.tool.common.exception.BaseRuntimeException;
import com.bruce.tool.common.exception.ExceptionUtils;
import com.bruce.tool.common.util.LogUtils;
import com.bruce.tool.common.util.string.JsonUtils;
import com.bruce.tool.common.util.string.StringUtils;
import com.bruce.tool.common.util.valid.ValidUtils;
import com.bruce.tool.push.aliyun.config.AliyunPusherConfig;
import com.bruce.tool.push.aliyun.constant.DeviceType;
import com.bruce.tool.push.aliyun.constant.OpenType;
import com.bruce.tool.push.aliyun.constant.PushErrorCode;
import com.bruce.tool.push.aliyun.constant.Target;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.util.Date;
import java.util.List;
import java.util.Objects;

/**
 * 功能 :
 *
 * @author : Bruce(刘正航) 11:15 AM 2018/12/3
 */
@Slf4j
@Component
public abstract class AliyunPusher {

    @Autowired
    protected AliyunPusherConfig aliyunPusherConfig;

    /**推送到ios**/
    public boolean push2ios(Message message){
        return execute(Target.DEVICE, DeviceType.IOS,message);
    }

    /**推送到android**/
    public boolean push2android(Message message){
        return execute(Target.DEVICE,DeviceType.ANDROID,message);
    }

    /**推送到所有类型终端设备**/
    public boolean push2device(Message message){
        return execute(Target.DEVICE,DeviceType.ALL,message);
    }

    /**推送到指定账户**/
    public boolean push2account(Message message){
        return execute(Target.ACCOUNT,DeviceType.ALL,message);
    }

    /**推送到指定账户**/
    public boolean push2alias(Message message){
        return execute(Target.ALIAS,DeviceType.ALL,message);
    }

    /**推送给自定义标签**/
    public boolean push2tag(Message message){
        return execute(Target.TAG,DeviceType.ALL,message);
    }

    /**推送给所有目标终端**/
    public boolean push2all(Message message){
        return execute(Target.ALL,DeviceType.ALL,message);
    }

    /**执行消息推送**/
    public boolean execute(Target target,DeviceType deviceType,Message message){
        // 校验配置内容
        ValidUtils.valid(aliyunPusherConfig);
        // 校验消息内容
        ValidUtils.valid(message);

        return push(initRequest(target, deviceType, message));
    }

    /**执行推送**/
    private boolean push(PushRequest pushRequest) {
        try {
            IClientProfile profile = DefaultProfile.getProfile(aliyunPusherConfig.getRegionId(), aliyunPusherConfig.getAccessKeyId(), aliyunPusherConfig.getAccessKeySecret());
            DefaultAcsClient client = new DefaultAcsClient(profile);
            PushResponse pushResponse = client.getAcsResponse(pushRequest);
            LogUtils.info(log,"消息推送,返回结果:{}", JsonUtils.objToStr(pushResponse));
            return true;
        } catch (Exception e) {
            ExceptionUtils.printStackTrace(e);
            return false;
        }
    }

    /**初始化请求对象**/
    private PushRequest initRequest(Target target, DeviceType deviceType, Message message) {
        PushRequest pushRequest = new PushRequest();
        // 推送目标
        initTarget(message, pushRequest, target, deviceType);
        // 推送消息配置
        initMessage(message, pushRequest);
        // 配置推送终端
        initDeviceInfo(message, pushRequest, deviceType);
        // 配置推送属性
        initPushConfig(message, pushRequest);

        return pushRequest;
    }

    /**配置推送属性**/
    private void initPushConfig(Message message, PushRequest pushRequest) {
        // 离线消息是否保存,若保存, 在推送时候，用户即使不在线，下一次上线则会收到
        if(Objects.nonNull(message.getStoreOffline()) ){
            pushRequest.setStoreOffline(message.getStoreOffline());
        }

        // 推送控制
        if(Objects.nonNull(aliyunPusherConfig.getDelay())){
            // 30秒之间的时间点, 也可以设置成你指定固定时间
            final Date pushDate = new Date(System.currentTimeMillis() + message.getDelay() * 1000);
            final String pushTime = ParameterHelper.getISO8601Time(pushDate);
            pushRequest.setPushTime(pushTime);
        }

        if(Objects.nonNull(message.getDelay())){
            // 30秒之间的时间点, 也可以设置成你指定固定时间
            final Date pushDate = new Date(System.currentTimeMillis() + message.getDelay() * 1000);
            final String pushTime = ParameterHelper.getISO8601Time(pushDate);
            pushRequest.setPushTime(pushTime);
        }

        if( Objects.nonNull(aliyunPusherConfig.getExpire()) ){
            // 12小时后消息失效, 不会再发送
            String expireTime = ParameterHelper.getISO8601Time(new Date(System.currentTimeMillis() + aliyunPusherConfig.getExpire() * 3600 * 1000));
            pushRequest.setExpireTime(expireTime);
        }

        if( Objects.nonNull(message.getExpire()) ){
            // 12小时后消息失效, 不会再发送
            String expireTime = ParameterHelper.getISO8601Time(new Date(System.currentTimeMillis() + message.getExpire() * 3600 * 1000));
            pushRequest.setExpireTime(expireTime);
        }
    }

    /**配置推送终端**/
    private void initDeviceInfo(Message message, PushRequest pushRequest, DeviceType deviceType) {
        if( DeviceType.IOS.equals(deviceType) || DeviceType.ALL.equals(deviceType) ){
            // 推送配置: IOS
            // iOS应用图标右上角角标
            pushRequest.setIOSBadge(message.getIOSBadge());
            //开启静默通知
            pushRequest.setIOSSilentNotification(false);
            // iOS通知声音
            pushRequest.setIOSMusic(message.getIOSMusic());
            //iOS10通知副标题的内容
            pushRequest.setIOSSubtitle(message.getIOSSubTitle());
            //指定iOS10通知Category
            pushRequest.setIOSNotificationCategory("iOS10 Notification Category");
            //是否允许扩展iOS通知内容
            pushRequest.setIOSMutableContent(true);
            // 消息推送时设备不在线（既与移动推送的服务端的长连接通道不通），则这条推送会做为通知，通过苹果的APNs通道送达一次。注意：离线消息转通知仅适用于生产环境
            pushRequest.setIOSRemind(true);
            //iOS消息转通知时使用的iOS通知内容，仅当iOSApnsEnv=PRODUCT && iOSRemind为true时有效
            pushRequest.setIOSRemindBody("iOSRemindBody");
            //通知的扩展属性(注意 : 该参数要以json map的格式传入,否则会解析出错)
            pushRequest.setIOSExtParameters(message.getIOSExt());

            //iOS的通知是通过APNs中心来发送的，需要填写对应的环境信息。"DEV" : 表示开发环境 "PRODUCT" : 表示生产环境
            if( StringUtils.isNotBlank(aliyunPusherConfig.getIOSApnsEnv()) ){
                pushRequest.setIOSApnsEnv(aliyunPusherConfig.getIOSApnsEnv());
            }
            if( Objects.nonNull(message.getIOSApnsEnv()) ){
                pushRequest.setIOSApnsEnv(message.getIOSApnsEnv().name());
            }
        }

        if( DeviceType.ANDROID.equals(deviceType) || DeviceType.ALL.equals(deviceType) ){
            // 推送配置: Android
            //通知的提醒方式 "VIBRATE" : 震动 "SOUND" : 声音 "BOTH" : 声音和震动 NONE : 静音
            pushRequest.setAndroidNotifyType(message.getNotifyType().name());
            //通知栏自定义样式0-100
            pushRequest.setAndroidNotificationBarType(1);
            //通知栏自定义样式0-100
            pushRequest.setAndroidNotificationBarPriority(1);
            //点击通知后动作 "APPLICATION" : 打开应用 "ACTIVITY" : 打开AndroidActivity "URL" : 打开URL "NONE" : 无跳转
            pushRequest.setAndroidOpenType(message.getOpenType().name());
            // Android通知音乐
            pushRequest.setAndroidMusic(message.getAndroidMusic());
            if(OpenType.ACTIVITY.equals(message.getOpenType())){
                // 设定通知打开的activity，仅当AndroidOpenType="Activity"有效
                pushRequest.setAndroidActivity(message.getAndroidActivity());
            }else if(OpenType.URL.equals(message.getOpenType())){
                //Android收到推送后打开对应的url,仅当AndroidOpenType="URL"有效
                pushRequest.setAndroidOpenUrl(message.getAndroidUrl());
            }
            if( StringUtils.isNotBlank(message.getAndroidExt()) ){
                // 设定android类型设备通知的扩展属性
                pushRequest.setAndroidExtParameters(message.getAndroidExt());
            }
        }
    }

    /**推送消息配置**/
    private void initMessage(Message message, PushRequest pushRequest) {
        pushRequest.setPushType(message.getMessageType().name());
        // 消息的标题
        pushRequest.setTitle(message.getTitle());
        // 消息的内容
        pushRequest.setBody(message.getMessage());
    }

    /**推送目标配置**/
    private void initTarget(Message message, PushRequest pushRequest, Target target, DeviceType deviceType) {
        String appKeys = aliyunPusherConfig.getAppKeys();
        if( !appKeys.contains(",") ){
            pushRequest.setAppKey(Long.valueOf(appKeys));
        }else{
            List<String> keys = StringUtils.splitToList(appKeys,",");
            if(CollectionUtils.isEmpty(keys)){
                throw new BaseRuntimeException(PushErrorCode.PE0001.name(),"推送Appkey异常,请检查配置");
            }
            if( keys.size() == 1 ){
                pushRequest.setAppKey(Long.valueOf(keys.get(0)));
            }
            pushRequest.setAppKey(getAppKey(keys));
        }
        /*设置推送协议和推送方法*/
        pushRequest.setProtocol(ProtocolType.HTTPS);
        pushRequest.setMethod(MethodType.POST);

        /*设置推送目标*/
        // 设备类型 ANDROID iOS ALL
        pushRequest.setDeviceType(deviceType.name());
        //推送目标: DEVICE:按设备推送 ALIAS : 按别名推送 ACCOUNT:按帐号推送  TAG:按标签推送; ALL: 广播推送
        pushRequest.setTarget(target.name());
        //根据Target来设定，如Target=DEVICE, 则对应的值为 设备id1,设备id2. 多个值使用逗号分隔.(帐号与设备有一次最多100个的限制)
        pushRequest.setTargetValue(message.getTargetValue());
    }

    /**子类负责获取其中一个**/
    public Long getAppKey(List<String> keys){
        // TODO 如果有多个key,则需要继承此类,实现自己的推送方法
        return Long.valueOf(keys.get(0));
    }

}
